﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Super64.Core.CPU.MIPS
{
    // TOOD: Figure out about float compare
    public enum MipsOpcode
    {
        UNKNOWN = 0, // Uknown op
        NOP,
        [OpcodeMeta(32, InstructionType.Immediate)]LB,  // Load Byte (Sbyte)
        [OpcodeMeta(36, InstructionType.Immediate)]LBU, // Load Byte Unsigned
        [OpcodeMeta(55, InstructionType.Immediate)]LD,  // Load Doubleword
        [OpcodeMeta(26, InstructionType.Immediate)]LDL, // Load Doubleword Left
        [OpcodeMeta(27, InstructionType.Immediate)]LDR, // Load Doubleword Right
        [OpcodeMeta(33, InstructionType.Immediate)]LH, // Load Halfword
        [OpcodeMeta(37, InstructionType.Immediate)]LHU, // Load Halfword Unsigned
        [OpcodeMeta(48, InstructionType.Immediate)]LL, // Load Linked Word
        [OpcodeMeta(52, InstructionType.Immediate)]LLD, // Load Linked Doubleword
        [OpcodeMeta(35, InstructionType.Immediate)]LW, // Load Word
        [OpcodeMeta(34, InstructionType.Immediate)]LWL, // Load Word Left
        [OpcodeMeta(39, InstructionType.Immediate)]LWU, // Load Word Right
        [OpcodeMeta(40, InstructionType.Immediate)]SB, // Store Byte
        [OpcodeMeta(56, InstructionType.Immediate)]SC, // Store Conditonal Word
        [OpcodeMeta(60, InstructionType.Immediate)]SCD, // Store Conditional Doubleword
        [OpcodeMeta(63, InstructionType.Immediate)]SD, // Store Doubleword
        [OpcodeMeta(44, InstructionType.Immediate)]SDL, // SDL!! Store Doubleword Left
        [OpcodeMeta(45, InstructionType.Immediate)]SDR, // Store Doubleword Right
        [OpcodeMeta(41, InstructionType.Immediate)]SH, // Store Halfword
        [OpcodeMeta(43, InstructionType.Immediate)]SW, // Store Word
        [OpcodeMeta(42, InstructionType.Immediate)]SWL, // Store Word Left
        [OpcodeMeta(46, InstructionType.Immediate)]SWR, // Store Word Right
        [OpcodeMeta(08, InstructionType.Immediate)]ADDI, // Add Immediate Word
        [OpcodeMeta(09, InstructionType.Immediate)]ADDIU, // Add Immediate Unsigned Word
        [OpcodeMeta(12, InstructionType.Immediate)]ANDI, // AND Immediate
        [OpcodeMeta(24, InstructionType.Immediate)]DADDI, // Doubleword Add Immediate
        [OpcodeMeta(25, InstructionType.Immediate)]DADDIU, // Doubleword Add Immediate Unsigned
        [OpcodeMeta(15, InstructionType.Immediate)]LUI, // Load Upper Immediate
        [OpcodeMeta(13, InstructionType.Immediate)]ORI, // Or Immediate
        [OpcodeMeta(10, InstructionType.Immediate)]SLTI, // Set on less than immediate
        [OpcodeMeta(11, InstructionType.Immediate)]SLTIU, // set on less than immedate unsigned
        [OpcodeMeta(14, InstructionType.Immediate)]XORI, // XOR Immediate
        [OpcodeMeta(04, InstructionType.Immediate)]BEQ, // Branch on Equal
        [OpcodeMeta(20, InstructionType.Immediate)]BEQL, // Branch on Equal Likley
        [OpcodeMeta(07, InstructionType.Immediate)]BGTZ, // branch on greater than zero
        [OpcodeMeta(23, InstructionType.Immediate)]BGTZL, // branch on greater thn zero likely
        [OpcodeMeta(06, InstructionType.Immediate)]BLEZ, // branch on less than or equal to zero
        [OpcodeMeta(22, InstructionType.Immediate)]BLEZL, // branch on less than or equal to zero likely
        [OpcodeMeta(05, InstructionType.Immediate)]BNE, // branch on not equal
        [OpcodeMeta(21, InstructionType.Immediate)]BNEL, // branch on not equal likely
        [OpcodeMeta(47, InstructionType.Immediate)]CACHE, // Cache
        [OpcodeMeta(53, InstructionType.Immediate)]LDC1, // Load Doubleword to Floating-Point
        [OpcodeMeta(49, InstructionType.Immediate)]LWC1, // Load Word to Floating-Point
        [OpcodeMeta(61, InstructionType.Immediate)]SDC1, // Store Doubleword from Floating-Point
        [OpcodeMeta(57, InstructionType.Immediate)]SWC1, // Store Word from Floating-Point
        [OpcodeMeta(24, InstructionType.CP0Register)]ERET, // Return from exception
        [OpcodeMeta(08, InstructionType.CP0Register)]TLBP, // Translation Lookaside Buffer Probe
        [OpcodeMeta(01, InstructionType.CP0Register)]TLBR, // Translation Lookaside Buffer Read
        [OpcodeMeta(02, InstructionType.CP0Register)]TLBWI, // Translation Lookaside Buffer Write Index
        [OpcodeMeta(06, InstructionType.CP0Register)]TLBWR, // Translation Lookaside Buffer Write Random
        [OpcodeMeta(00, InstructionType.CP0RegisterRS)]MFC0, // Move word from CP0
        [OpcodeMeta(04, InstructionType.CP0RegisterRS)]MTC0, // Move word to CP0
        [OpcodeMeta(05, InstructionType.FPURegister)]FABS, // floating-point ABSolute value
        [OpcodeMeta(00, InstructionType.FPURegister)]FADD, // floating-point ADD
        [OpcodeMeta(10, InstructionType.FPURegister)]CEILL, // floating-point CEILing convert to Long fixed-point
        [OpcodeMeta(14, InstructionType.FPURegister)]CEILW, // floating-point CEILing convert to Word fixed-point
        [OpcodeMeta(33, InstructionType.FPURegister)]CVTD, // floating-point ConVerT to Double floating-point
        [OpcodeMeta(37, InstructionType.FPURegister)]CVTL, // floating-point ConVerT to Long fixed-point
        [OpcodeMeta(32, InstructionType.FPURegister)]CVTS, // floating-point ConVerT to Single floating-point
        [OpcodeMeta(36, InstructionType.FPURegister)]CVTW, // floating-point ConVerT to Word fixed-point
        [OpcodeMeta(03, InstructionType.FPURegister)]FDIV, // floating-point DIVide
        [OpcodeMeta(11, InstructionType.FPURegister)]FLOORL, // floating-point FLOOR convert to Long fixed-point
        [OpcodeMeta(15, InstructionType.FPURegister)]FLOORW, // floating-point FLOOR convert to Word fixed-point
        [OpcodeMeta(06, InstructionType.FPURegister)]MOV, // floating-point MOVe
        [OpcodeMeta(02, InstructionType.FPURegister)]FMUL, // floating-point MULtiply
        [OpcodeMeta(07, InstructionType.FPURegister)]NEG, // floating-point NEGate
        [OpcodeMeta(08, InstructionType.FPURegister)]ROUNDL, // floating-point ROUND to Long fixed-point
        [OpcodeMeta(12, InstructionType.FPURegister)]ROUNDW, // floating-point ROUND to Word fixed-point
        [OpcodeMeta(04, InstructionType.FPURegister)]SQRT, // floating-point SQuare RooT
        [OpcodeMeta(01, InstructionType.FPURegister)]FSUB, // floating-point SUBtract
        [OpcodeMeta(09, InstructionType.FPURegister)]TRUNCL, // floating-point TRUNCate to Long fixed-point
        [OpcodeMeta(13, InstructionType.FPURegister)]TRUNCW, // floating-point TRUNCate to Word fixed-point
        [OpcodeMeta(08, InstructionType.FPURegisterRS)]BC1FX, // Branch on FP False (OR) Branch on FP False Likley  (if ND = 1) OR (Branch on FP True )
        [OpcodeMeta(02, InstructionType.FPURegisterRS)]CFC1, // Move control word From Floating-Point
        [OpcodeMeta(06, InstructionType.FPURegisterRS)]CTC1, // Move control word To Floating-Point
        [OpcodeMeta(01, InstructionType.FPURegisterRS)]DMFC1, // Doubleword Move From Floating-Point
        [OpcodeMeta(05, InstructionType.FPURegisterRS)]DMTC1, // Doubleword Move To Floating-Point
        [OpcodeMeta(00, InstructionType.FPURegisterRS)]MFC1, // Move Word From Floating-Point
        [OpcodeMeta(04, InstructionType.FPURegisterRS)]MTC1, // Move Word to Floating-Point
        [OpcodeMeta(02, InstructionType.Jump)]J, // Jump lol
        [OpcodeMeta(03, InstructionType.Jump)]JAL,
        [OpcodeMeta(15, InstructionType.Register)]SYNC, // Synchronize shared memory
        [OpcodeMeta(32, InstructionType.Register)]ADD, // Add word
        [OpcodeMeta(33, InstructionType.Register)]ADDU, // ADD Unsigned Word
        [OpcodeMeta(36, InstructionType.Register)]AND, // And
        [OpcodeMeta(44, InstructionType.Register)]DADD, // Doubleword Add
        [OpcodeMeta(45, InstructionType.Register)]DADDU, // Doubleword Add Unsigned
        [OpcodeMeta(30, InstructionType.Register)]DDIV, // Doubleword Divide
        [OpcodeMeta(31, InstructionType.Register)]DDIVU, // Doubleword Divide Unsigned
        [OpcodeMeta(26, InstructionType.Register)]DIV, // Divide Word
        [OpcodeMeta(27, InstructionType.Register)]DIVU, // Divide Unsigned Word
        [OpcodeMeta(28, InstructionType.Register)]DMULT, // Doubleword Multiply
        [OpcodeMeta(29, InstructionType.Register)]DMULTU, // Doubleword Multiply Unsigned
        [OpcodeMeta(56, InstructionType.Register)]DSLL, // Doubleword Shift Left Logical
        [OpcodeMeta(60, InstructionType.Register)]DSLL32, // Doubleword Shift Left Logical +32
        [OpcodeMeta(20, InstructionType.Register)]DSLLV, // Doubleword Shift Left Logical Variable
        [OpcodeMeta(59, InstructionType.Register)]DSRA, // Doubleword Shift Right Arithmetic
        [OpcodeMeta(63, InstructionType.Register)]DSRA32, // Doubleword Shift Right Arithmetic +32
        [OpcodeMeta(23, InstructionType.Register)]DSRAV, // Doubleword Shift Right Arithmetic Variable
        [OpcodeMeta(58, InstructionType.Register)]DSRL, // Dobuleword Shift Right Logical
        [OpcodeMeta(62, InstructionType.Register)]DSRL32, // Doubleword Shift Right Logical +32
        [OpcodeMeta(22, InstructionType.Register)]DSRLV, // Doubleword Shift Right Logical Variable
        [OpcodeMeta(46, InstructionType.Register)]DSUB, // Doubleword Subtract
        [OpcodeMeta(47, InstructionType.Register)]DSUBU, // Doubleword Subtract Unsigned
        [OpcodeMeta(16, InstructionType.Register)]MFHI, // Move from HI register
        [OpcodeMeta(18, InstructionType.Register)]MFLO, // Move from LO register
        [OpcodeMeta(17, InstructionType.Register)]MTHI, // Move to HI register
        [OpcodeMeta(19, InstructionType.Register)]MTLO, // Move to LO register
        [OpcodeMeta(24, InstructionType.Register)]MULT, // Multiply word
        [OpcodeMeta(25, InstructionType.Register)]MULTU, // Multiply Unsigned word
        [OpcodeMeta(39, InstructionType.Register)]NOR, // Not Or
        [OpcodeMeta(37, InstructionType.Register)]OR, // Or
        [OpcodeMeta(00, InstructionType.Register)]SLL, // Shift word left logical
        [OpcodeMeta(04, InstructionType.Register)]SLLV, // Shift word left logical variable
        [OpcodeMeta(42, InstructionType.Register)]SLT, // set on less than
        [OpcodeMeta(43, InstructionType.Register)]SLTU, // set on less than unsigned
        [OpcodeMeta(03, InstructionType.Register)]SRA, // Shift word right arithmetic
        [OpcodeMeta(07, InstructionType.Register)]SRAV, // Shift word right arithmetic variable
        [OpcodeMeta(02, InstructionType.Register)]SRL, // shift word right logical
        [OpcodeMeta(06, InstructionType.Register)]SRLV, // shift word right logocal variable
        [OpcodeMeta(34, InstructionType.Register)]SUB, // subtract word
        [OpcodeMeta(35, InstructionType.Register)]SUBU, // subtract unsigned word
        [OpcodeMeta(38, InstructionType.Register)]XOR, // XOR
        [OpcodeMeta(09, InstructionType.Register)]JALR, // jump and link register
        [OpcodeMeta(08, InstructionType.Register)]JR, // jump register
        [OpcodeMeta(13, InstructionType.Register)]BREAK, // Breakpoint
        [OpcodeMeta(12, InstructionType.Register)]SYSCALL, // System call
        [OpcodeMeta(52, InstructionType.Register)]TEQ, // Trap if equal
        [OpcodeMeta(48, InstructionType.Register)]TGE, // trap if greater or equal
        [OpcodeMeta(49, InstructionType.Register)]TGEU, // Trap if Greater or Equal Unsigned
        [OpcodeMeta(50, InstructionType.Register)]TLT, // Trap if Less Than
        [OpcodeMeta(51, InstructionType.Register)]TLTU, // Trap if Less Than Unsigned
        [OpcodeMeta(54, InstructionType.Register)]TNE, // Trap if Not Equal
        [OpcodeMeta(01, InstructionType.RegisterRT)]BGEZ, // Branch on Greater than or Equal to Zero
        [OpcodeMeta(17, InstructionType.RegisterRT)]BGEZAL, // Branch on greater than or equal to zero and link
        [OpcodeMeta(19, InstructionType.RegisterRT)]BGEALL, //  branch on greater than or equal to zero and link likely
        [OpcodeMeta(03, InstructionType.RegisterRT)]BGEZL, // branch on greater than or equal to zero likely
        [OpcodeMeta(00, InstructionType.RegisterRT)]BLTZ, // branch on less than zero
        [OpcodeMeta(16, InstructionType.RegisterRT)]BLTZAL, // branch on less than zero and link
        [OpcodeMeta(18, InstructionType.RegisterRT)]BLTZALL, // branch on less than zero and link likely
        [OpcodeMeta(02, InstructionType.RegisterRT)]BLTZL, // branch on less than zero likely
        [OpcodeMeta(12, InstructionType.RegisterRT)]TEQI, // trap if equal immediate
        [OpcodeMeta(08, InstructionType.RegisterRT)]TGEI, // trap if greater or equal immediate
        [OpcodeMeta(09, InstructionType.RegisterRT)]TGEIU, // Trap if Greater or Equal Immediate Unsigned
        [OpcodeMeta(10, InstructionType.RegisterRT)]TLTI, // Trap if Less Than Immediate
        [OpcodeMeta(11, InstructionType.RegisterRT)]TLTIU, // Trap if Less Than Immediate Unsigned
        [OpcodeMeta(14, InstructionType.RegisterRT)]TNEI, // Trap if Not Equal Immediate
    }
}
